﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using diagnostics = System.Diagnostics;

namespace JScriptSuite.QA.Lib.System
{
    class ArrayInterfaces
    {
        internal static JResultItem AllTests()
        {
            return JResultItem.CreateInstance("ArrayInterfaces")
                .Push(CompilerTests(), IsOperatorTests(), InstanceOfTests());
        }

        static JResultItem CompilerTests()
        {
            I<Base, Dev1>[] ib1 = new C<Base, Dev1>[0];

            return JResultItem.CreateInstance("CompilerTests")
                .Push(
                    new Dev1[0] is Base[],
                    new Base[0] is Dev1[],
                    ib1 is IList<I<Base, Dev1>>,
                    ib1 is IList<I<Dev2, Base>>,
                    new C<Base, Dev1>[0] is IList<I<Dev2, Base>>,
                    new C<Base, Dev1>[0] is IList<I<Base, Dev1>>,
                    new C<Base, Dev1>[0] is IList<I<Dev1, Base>>,
                    new C<Base, Dev1>[0] is IList<I<Base, Base>>,
                    new C<Dev2, Dev1>[0] is IList<I<Base, Dev1>>
                );
        }

        static JResultItem IsOperatorTests()
        {
            I<Base, Dev1>[] ib1 = new C<Base, Dev1>[0];
            // I<Base, Base>[] ibb = new C<Base, Dev1>[0];
            return JResultItem.CreateInstance("IsOperatorTests")
                .Push(
                    /*(object)new Dev1[0] is Dev1[],
                    (object)new Dev1[0] is Base[],
                    (object)new Base[0] is Dev1[],*/
                    (object)ib1 is C<Base, Dev1>[],
                    // (object)ib1 is I<Base, Dev1>[],
                    (object)ib1 is IList<I<Base, Dev1>>,
                    // (object)new C<Base, Dev1>[0] is I<Base, Base>[],
                    // (object)new C<Dev2, Base>[0] is IList<I<Dev2, Base>> /*,
                    (object)ib1 is IList<I<Dev2, Base>>,
                    (object)new C<Base, Dev1>[0] is IList<I<Dev2, Base>>/*,
                    (object)new C<Base, Dev1>[0] is IList<I<Base, Dev1>>,
                    (object)new C<Base, Dev1>[0] is IList<I<Dev1, Base>>*/,
                    (object)new C<Base, Dev1>[0] is IList<I<Base, Base>>/*,
                    (object)new C<Dev2, Dev1>[0] is IList<I<Base, Dev1>>
                */);
        }

        static JResultItem InstanceOfTests()
        {
            I<Base, Dev1>[] ib1 = new C<Base, Dev1>[0];
            return JResultItem.CreateInstance("InstanceOfTests")
                .Push(
                    typeof(Base[]).IsInstanceOfType((object)new Dev1[0]),
                    typeof(Dev1[]).IsInstanceOfType((object)new Base[0]),
                    typeof(I<Base, Dev1>[]).IsInstanceOfType((object)ib1),
                    typeof(I<Dev2, Base>[]).IsInstanceOfType((object)ib1),
                    typeof(I<Dev2, Base>[]).IsInstanceOfType((object)new C<Base, Dev1>[0]),
                    typeof(I<Base, Dev1>[]).IsInstanceOfType((object)new C<Base, Dev1>[0]),
                    typeof(I<Dev1, Base>[]).IsInstanceOfType((object)new C<Base, Dev1>[0]),
                    typeof(I<Base, Base>[]).IsInstanceOfType((object)new C<Base, Dev1>[0]),
                    typeof(I<Base, Dev1>[]).IsInstanceOfType((object)new C<Dev2, Dev1>[0])
                );
        }

        class Base
        {
        }

        class Dev1 : Base
        {

        }

        class Dev2 : Base
        {

        }

        class C<T1, T2> : I<T1, T2>
        {
            T1 I<T1, T2>.Data1
            {
                set { throw new NotImplementedException(); }
            }

            T2 I<T1, T2>.Data2
            {
                get { throw new NotImplementedException(); }
            }
        }

        interface I<in T1, out T2>
        {
            T1 Data1 { set; }   // contravariant
            T2 Data2 { get; }   // covariant
        }

    }
}
